package com.genokon.service.impl;

import com.genokon.dto.VarComputeDto;
import com.genokon.dto.VarParams;
import com.genokon.dto.VariationDto;
import com.genokon.entry.*;
import com.genokon.mapper.*;
import com.genokon.service.VariationService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author by baichaoda
 * @date 2020/11/3 13:10
 */
@Slf4j
@Service("variationService")
public class VariationServiceImpl implements VariationService {
    @Resource
    private VariationInfoMapper variationInfoMapper;
    @Resource
    private VariationEntrezIdMapper variationEntrezIdMapper;
    @Resource
    private VariationSymbolMapper variationSymbolMapper;
    @Resource
    private VariationRsMapper variationRsMapper;
    @Resource
    private VariationSampleMapper variationSampleMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long addVariation(VariationDto dto) throws Exception {
        if (StringUtils.isEmpty(dto.getSampleId())){
            throw new Exception("样本id不允许为空");
        }
        Long varId = getVariationId(dto);
        //存在变异点，则只插入样本
        if (varId != null){
            int reInt = 0;
            Map<String, Object> sampleMap = new HashMap<>(1);
            sampleMap.put("var_id", varId);
            sampleMap.put("sample_id", dto.getSampleId());
            if (CollectionUtils.isEmpty(variationSampleMapper.selectByMap(sampleMap))){
                reInt = insertSample(varId, dto.getSampleId(), dto.getBatchId());
            }
            reInt += insertrs(varId, dto.getRsIds());
            reInt += insertEntrez(varId, dto.getEntrezIds());
            reInt += insertSymbol(varId, dto.getSymbols());
            return reInt == 0? 0L:varId;
        }
        //不存在变异点 插入新的
        GeneVariationInfo info = new GeneVariationInfo();
        info.setStart(dto.getStart());
        info.setEnd(dto.getEnd());
        info.setChr(dto.getChr());
        info.setAlt(dto.getAlt());
        info.setRef(dto.getRef());
        info.setGenotype(dto.getGenotype());
        variationInfoMapper.insert(info);

        varId = info.getId();
        insertSample(varId, dto.getSampleId(), dto.getBatchId());
        insertrs(varId, dto.getRsIds());
        insertEntrez(varId, dto.getEntrezIds());
        insertSymbol(varId, dto.getSymbols());

        return varId;
    }

    private int insertSample(Long varId, String sampleId, String batchId){
        GeneVariationSample sample = new GeneVariationSample();
        sample.setVarId(varId);
        sample.setSampleId(sampleId);
        sample.setBatchId(batchId);
        variationSampleMapper.insert(sample);
        return 1;
    }

    private int insertrs(Long varId, List<String> rsIds){
        AtomicInteger ins = new AtomicInteger();
        if (CollectionUtils.isEmpty(rsIds)){
            return ins.get();
        }
        rsIds.forEach(item->{
            Map<String, Object> map = new HashMap<>(1);
            map.put("var_id", varId);
            map.put("rs", item);
            if (CollectionUtils.isEmpty(variationRsMapper.selectByMap(map))){
                GeneVariationRs rs = new GeneVariationRs();
                rs.setRs(item);
                rs.setVarId(varId);
                variationRsMapper.insert(rs);
                ins.getAndIncrement();
            }
        });
        return ins.get();
    }
    private int insertEntrez(Long varId, List<String> entrezIds){
        AtomicInteger ins = new AtomicInteger();
        if (CollectionUtils.isEmpty(entrezIds)){
            return ins.get();
        }
        entrezIds.forEach(item->{
            Map<String, Object> map = new HashMap<>(1);
            map.put("var_id", varId);
            map.put("entrez_id", item);
            if (CollectionUtils.isEmpty(variationEntrezIdMapper.selectByMap(map))){
                GeneVariationEntrezId enz = new GeneVariationEntrezId();
                enz.setEntrezId(item);
                enz.setVarId(varId);
                variationEntrezIdMapper.insert(enz);
                ins.getAndIncrement();
            }
        });
        return ins.get();
    }
    private int insertSymbol(Long varId, List<String> symbols){
        AtomicInteger ins = new AtomicInteger();
        if (CollectionUtils.isEmpty(symbols)){
            return ins.get();
        }
        symbols.forEach(item->{
            Map<String, Object> map = new HashMap<>(1);
            map.put("var_id", varId);
            map.put("symbol", item);
            if (CollectionUtils.isEmpty(variationSymbolMapper.selectByMap(map))){
                GeneVariationSymbol symbol = new GeneVariationSymbol();
                symbol.setSymbol(item);
                symbol.setVarId(varId);
                variationSymbolMapper.insert(symbol);
                ins.getAndIncrement();
            }
        });
        return ins.get();
    }

    @Override
    public List<VariationDto> getVariation(VarParams params) {
        Map<String, String> con = new HashMap<>(1);

        if (!StringUtils.isEmpty(params.getRs())){
            con.put("rs", params.getRs());
        }
        if (!StringUtils.isEmpty(params.getEntrez())){
            con.put("entrez", params.getEntrez());
        }
        if (!StringUtils.isEmpty(params.getRs())){
            con.put("symbol", params.getSymbol());
        }

        return variationInfoMapper.selectByKey(con);
    }

    @Override
    public VarComputeDto getVariationById(GeneVariationInfo params) {
        Long id = getVariationId(params);
        if (id == null){
            return null;
        }
        List<VariationDto> rs = variationInfoMapper.selectInfoById(id);
        VarComputeDto result = new VarComputeDto();
        result.setRate(rateVariation(params));
        result.setResults(rs);
        return result;
    }

    @Override
    public Double rateVariation(GeneVariationInfo params) {
        Integer smCount = variationSampleMapper.countSample();
        Long id = getVariationId(params);
        Integer varCount = variationSampleMapper.countSampleByVarId(id);
        return (double) varCount / smCount;
    }

    private Long getVariationId(GeneVariationInfo params){
        Map<String, Object> map = new HashMap<>(1);
        map.put("chr", params.getChr());
        map.put("start", params.getStart());
        map.put("end", params.getEnd());
        map.put("ref", params.getRef());
        map.put("alt", params.getAlt());
        map.put("genotype", params.getGenotype());

        List<GeneVariationInfo> rs = variationInfoMapper.selectByMap(map);
        if (CollectionUtils.isEmpty(rs)){
            return null;
        }

        return rs.get(0).getId();
    }

}
